namespace ScrumSprintMonitor.UI.Wpf
{
	#region #using Directives

	using System;
	using System.Collections.Generic;
	using System.Collections.ObjectModel;
	using System.Linq;
	using System.Windows;
	using System.Windows.Controls;
	using System.Windows.Media;

	using Design;

	using Infrastructure;
	using Infrastructure.Configuration;

	using Ninject.Core;
	using Ninject.Core.Behavior;

	using Properties;

	using Rhino.Mocks;

	using ViewModels;

	#endregion

	public class NinjectUiDesignTimeModule : StandardModule
	{
		/// <summary>
		/// Loads the module into the kernel.
		/// </summary>
		public override void Load()
		{
			try
			{
				SetupDesignTimeBindings();
			}
			catch (Exception e)
			{
				MessageBox.Show(e.Message, GetType().FullName);

				throw;
			}
		}

		private void SetupDesignTimeBindings()
		{
			Bind<IPresentationConfiguration>().To<TestAssetLibrary.HardcodedPresentationConfiguration>().Using<SingletonBehavior>();

			var monitorViewModel = MockRepository.GenerateStub<IMonitorViewModel>();
			var sprintTitleViewModel = MockRepository.GenerateStub<ISprintTitleViewModel>();
			var sprintStatsViewModel = MockRepository.GenerateStub<ISprintStatsViewModel>();
			var backlogItemCountChartViewModel = MockRepository.GenerateStub<IBacklogItemCountChartViewModel>();
			var userStoryCountChartViewModel = MockRepository.GenerateStub<IUserStoryCountChartViewModel>();
			var sprintHoursChartViewModel = MockRepository.GenerateStub<ISprintHoursChartViewModel>();
			var unassignedTeamMember = MockRepository.GenerateStub<ITeamMemberViewModel>();
			var firstTeamMember = MockRepository.GenerateStub<ITeamMemberViewModel>();
			var secondTeamMember = MockRepository.GenerateStub<ITeamMemberViewModel>();
			var thirdTeamMember = MockRepository.GenerateStub<ITeamMemberViewModel>();
			var backlogItemsPieChartData = new ObservableCollection<PieChartValue<int>>(new[]
			                                                                            	{
			                                                                            		new PieChartValue<int>
			                                                                            			{
			                                                                            				Value = 1
			                                                                            			}, new PieChartValue<int>
			                                                                            			   	{
			                                                                            			   		Value = 1
			                                                                            			   	},
			                                                                            		new PieChartValue<int>
			                                                                            			{
			                                                                            				Value = 1
			                                                                            			}, new PieChartValue<int>
			                                                                            			   	{
			                                                                            			   		Value = 1
			                                                                            			   	}
			                                                                            	});
			var workloadPieChartData = new ObservableCollection<PieChartValue<double>>(new[]
			                                                                           	{
			                                                                           		new PieChartValue<double>
			                                                                           			{
			                                                                           				Value = 0.0
			                                                                           			}, new PieChartValue<double>
			                                                                           			   	{
			                                                                           			   		Value =
			                                                                           			   			1.0
			                                                                           			   	},
			                                                                           		new PieChartValue<double>
			                                                                           			{
			                                                                           				Value = 1.0
			                                                                           			}, new PieChartValue<double>
			                                                                           			   	{
			                                                                           			   		Value =
			                                                                           			   			1.0
			                                                                           			   	}
			                                                                           	});


			monitorViewModel.Stub(m => m.DeploymentVersion).Return("1.0.0.78");

			sprintTitleViewModel.Stub(m => m.CurrentSprintName).Return("Sprint 4");
			sprintTitleViewModel.Stub(m => m.ProjectName).Return("scrumsprintmonitor");
			sprintTitleViewModel.Stub(m => m.PlaceholderOrientation).Return(Orientation.Horizontal);
			sprintTitleViewModel.Stub(m => m.Visibility).Return(Visibility.Visible);
			sprintTitleViewModel.Stub(m => m.SprintPercentageCovered).Return(0.75);

			// Setup Unassigned ITeamMemberViewModel

			// Setup Unassigned ITeamMemberViewModel.RemainingWorkload
			unassignedTeamMember.Stub(t => t.RemainingPotentialSprintHours).Return(10);
			unassignedTeamMember.Stub(t => t.RemainingSprintWork).Return(8);
			unassignedTeamMember.Stub(t => t.RemainingUnassignedSprintWork).Return(0);
			unassignedTeamMember.Stub(t => t.RemainingWorkItemCount).Return(3);
			unassignedTeamMember.Stub(t => t.DisplayName).Return("<Unassigned>").Repeat.Any();

			// Setup 1st ITeamMemberViewModel
			firstTeamMember.Stub(t => t.DisplayName).Return("Pedro Sampaio").Repeat.Any();
			firstTeamMember.Stub(t => t.AvatarImageSource).Return(new DrawingImage(new GeometryDrawing
			                                                                       	{
			                                                                       		Geometry =
			                                                                       			new RectangleGeometry(new Rect(new Size(80, 80))),
			                                                                       		Brush = Brushes.Purple
			                                                                       	})).Repeat.Any();

			// Setup 1st ITeamMemberViewModel.RemainingWorkload
			firstTeamMember.Stub(t => t.RemainingPotentialSprintHours).Return(56);
			firstTeamMember.Stub(t => t.RemainingSprintWork).Return(168);
			firstTeamMember.Stub(t => t.RemainingUnassignedSprintWork).Return(4);
			firstTeamMember.Stub(t => t.IncludesFreeBusyInformation).Return(false);
			firstTeamMember.Stub(t => t.RemainingSprintWorkWithUnassigned).Return(firstTeamMember.RemainingSprintWork +
			                                                                      firstTeamMember.RemainingUnassignedSprintWork);
			firstTeamMember.Stub(t => t.RemainingWorkItemCount).Return(6);
			firstTeamMember.Stub(t => t.DoneWorkItemCount).Return(6);
			firstTeamMember.Stub(t => t.DoneSprintWork).Return(12.0);
			firstTeamMember.Stub(t => t.BacklogItemsPieChartData).Return(backlogItemsPieChartData);
			firstTeamMember.Stub(t => t.WorkloadPieChartData).Return(workloadPieChartData);

			// Setup 2nd ITeamMemberViewModel
			secondTeamMember.Stub(t => t.DisplayName).Return("Eduardo Laranjeira").Repeat.Any();

			// Setup 2nd ITeamMemberViewModel.RemainingWorkload
			secondTeamMember.Stub(t => t.RemainingPotentialSprintHours).Return(56);
			secondTeamMember.Stub(t => t.RemainingSprintWork).Return(79);
			secondTeamMember.Stub(t => t.RemainingUnassignedSprintWork).Return(0);
			secondTeamMember.Stub(t => t.IncludesFreeBusyInformation).Return(false);
			secondTeamMember.Stub(t => t.RemainingSprintWorkWithUnassigned).Return(secondTeamMember.RemainingSprintWork +
			                                                                       secondTeamMember.RemainingUnassignedSprintWork);
			secondTeamMember.Stub(t => t.RemainingWorkItemCount).Return(9);
			secondTeamMember.Stub(t => t.DoneWorkItemCount).Return(6);
			secondTeamMember.Stub(t => t.DoneSprintWork).Return(12.0);
			secondTeamMember.Stub(t => t.BacklogItemsPieChartData).Return(backlogItemsPieChartData);
			secondTeamMember.Stub(t => t.WorkloadPieChartData).Return(workloadPieChartData);

			// Setup 3rd ITeamMemberViewModel
			thirdTeamMember.Stub(t => t.DisplayName).Return("Samuel Moura").Repeat.Any();

			// Setup 3rd ITeamMemberViewModel.RemainingWorkload
			thirdTeamMember.Stub(t => t.RemainingPotentialSprintHours).Return(56);
			thirdTeamMember.Stub(t => t.RemainingSprintWork).Return(73);
			thirdTeamMember.Stub(t => t.RemainingUnassignedSprintWork).Return(1);
			thirdTeamMember.Stub(t => t.IncludesFreeBusyInformation).Return(true);
			thirdTeamMember.Stub(t => t.RemainingSprintWorkWithUnassigned).Return(thirdTeamMember.RemainingSprintWork +
			                                                                      thirdTeamMember.RemainingUnassignedSprintWork);
			thirdTeamMember.Stub(t => t.RemainingWorkItemCount).Return(8);
			thirdTeamMember.Stub(t => t.DoneWorkItemCount).Return(6);
			thirdTeamMember.Stub(t => t.DoneSprintWork).Return(12.0);
			thirdTeamMember.Stub(t => t.BacklogItemsPieChartData).Return(backlogItemsPieChartData);
			thirdTeamMember.Stub(t => t.WorkloadPieChartData).Return(workloadPieChartData);

			// Setup current sprint
			var teamMembersList = new List<ITeamMemberViewModel>
			                      	{
			                      		firstTeamMember,
			                      		secondTeamMember,
			                      		thirdTeamMember
			                      	};
			const int backlogItemCount = 347;
			const int userStoryCount = 243;

			backlogItemCountChartViewModel.Stub(m => m.ReadyForTestWork_BacklogItemCount).Return(238);
			backlogItemCountChartViewModel.Stub(m => m.ActiveWork_BacklogItemCount).Return(36);
			backlogItemCountChartViewModel.Stub(m => m.NotDoneWork_BacklogItemCount).Return(backlogItemCount -
			                                                                                (backlogItemCountChartViewModel.ActiveWork_BacklogItemCount +
			                                                                                 backlogItemCountChartViewModel.ReadyForTestWork_BacklogItemCount));

			userStoryCountChartViewModel.Stub(m => m.ReadyForTestWork_UserStoryCount).Return(142);
			userStoryCountChartViewModel.Stub(m => m.ActiveWork_UserStoryCount).Return(49);
			userStoryCountChartViewModel.Stub(m => m.NotDoneWork_UserStoryCount).Return(userStoryCount -
			                                                                            (userStoryCountChartViewModel.ActiveWork_UserStoryCount +
			                                                                             userStoryCountChartViewModel.ReadyForTestWork_UserStoryCount));

			sprintHoursChartViewModel.Stub(m => m.ReadyForTestWork_TotalHours).Return(1694.25);
			sprintHoursChartViewModel.Stub(m => m.ActiveWork_TotalHoursDone).Return(390);
			sprintHoursChartViewModel.Stub(m => m.ActiveWork_TotalHoursRemaining).Return(375.0);
			sprintHoursChartViewModel.Stub(m => m.NotDoneWork_TotalHours).Return(712);

			sprintStatsViewModel.Stub(m => m.AvailableHours).Return(1055);
			sprintStatsViewModel.Stub(m => m.TimeIncludesFreeBusyInformation).Return(teamMembersList.All(x => x.IncludesFreeBusyInformation));
			sprintStatsViewModel.Stub(m => m.IsAheadOfSchedule).Return(sprintStatsViewModel.AvailableHours >=
			                                                           (sprintHoursChartViewModel.NotDoneWork_TotalHours +
			                                                            sprintHoursChartViewModel.ActiveWork_TotalHoursRemaining));
			sprintStatsViewModel.Stub(m => m.DifferenceToSchedule).Return(
				Math.Abs(sprintStatsViewModel.AvailableHours -
				         (sprintHoursChartViewModel.NotDoneWork_TotalHours + sprintHoursChartViewModel.ActiveWork_TotalHoursRemaining)));
			sprintStatsViewModel.Stub(m => m.AverageResolutionTime).Return(sprintHoursChartViewModel.ReadyForTestWork_TotalHours /
			                                                               backlogItemCountChartViewModel.ReadyForTestWork_BacklogItemCount);

			monitorViewModel.Stub(m => m.SprintStatus).Return(SprintStatus.OK);
			monitorViewModel.Stub(m => m.SprintMode).Return(SprintMode.Sprinting);
			monitorViewModel.Stub(m => m.LastRefresh).Return(SystemTime.Now());
			monitorViewModel.Stub(m => m.LastUpdate).Return(SystemTime.Now() - TimeSpan.FromMinutes(1.5));

			var teamMembersListViewModel = MockRepository.GenerateStub<ITeamMembersListViewModel>();
			teamMembersListViewModel.Stub(m => m.UnassignedWork).Return(unassignedTeamMember);
			teamMembersListViewModel.Stub(m => m.TeamMembersIncludingUnassigned).Return(new ObservableCollection<ITeamMemberViewModel>
			                                                                            	{
			                                                                            		unassignedTeamMember,
			                                                                            		firstTeamMember,
			                                                                            		secondTeamMember,
			                                                                            		thirdTeamMember
			                                                                            	});
			teamMembersListViewModel.Stub(m => m.NumberOfColumnsInGridView).Return(Math.Max(1,
			                                                                                (int)
			                                                                                Math.Sqrt(
			                                                                                	teamMembersListViewModel.TeamMembersIncludingUnassigned.Count)));

			var sprintHoursPieChartData = new ObservableCollection<IWorkItemHoursPieChartData>
			                              	{
			                              		CreateWorkItemHoursPieChartData(
			                              			Resources.WorkItemState_ReadyForTest,
			                              			sprintHoursChartViewModel.ReadyForTestWork_TotalHours),
			                              		CreateWorkItemHoursPieChartData(
			                              			Resources.WorkItemState_Active_Done,
			                              			sprintHoursChartViewModel.ActiveWork_TotalHoursDone),
			                              		CreateWorkItemHoursPieChartData(
			                              			Resources.WorkItemState_Active_Remaining,
			                              			sprintHoursChartViewModel.ActiveWork_TotalHoursRemaining),
			                              		CreateWorkItemHoursPieChartData(
			                              			Resources.WorkItemState_NotDone,
			                              			sprintHoursChartViewModel.NotDoneWork_TotalHours)
			                              	};
			sprintHoursChartViewModel.Stub(x => x.Caption).Return("Work");
			sprintHoursChartViewModel.Stub(x => x.PieChartData).Return(sprintHoursPieChartData);
			Bind<ISprintHoursChartViewModel>().ToConstant(sprintHoursChartViewModel);

			var backlogItemCountPieChartData = new ObservableCollection<IWorkItemCountPieChartData>
			                                   	{
			                                   		CreateWorkItemCountPieChartData(
			                                   			Resources.WorkItemState_ReadyForTest,
			                                   			backlogItemCountChartViewModel.
			                                   				ReadyForTestWork_BacklogItemCount,
			                                   			sprintHoursPieChartData[0]),
			                                   		CreateWorkItemCountPieChartData(string.Empty, 0,
			                                   		                                sprintHoursPieChartData[1]),
			                                   		CreateWorkItemCountPieChartData(
			                                   			Resources.WorkItemState_Active,
			                                   			backlogItemCountChartViewModel.
			                                   				ActiveWork_BacklogItemCount, sprintHoursPieChartData[2]),
			                                   		CreateWorkItemCountPieChartData(
			                                   			Resources.WorkItemState_NotDone,
			                                   			backlogItemCountChartViewModel.
			                                   				NotDoneWork_BacklogItemCount, sprintHoursPieChartData[3])
			                                   	};
			backlogItemCountChartViewModel.Stub(x => x.Caption).Return("Backlog Items");
			backlogItemCountChartViewModel.Stub(x => x.PieChartData).Return(backlogItemCountPieChartData);
			Bind<IBacklogItemCountChartViewModel>().ToConstant(backlogItemCountChartViewModel);

			var userStoryCountPieChartData = new ObservableCollection<IWorkItemCountPieChartData>
			                                 	{
			                                 		CreateWorkItemCountPieChartData(
			                                 			Resources.WorkItemState_ReadyForTest,
			                                 			userStoryCountChartViewModel.
			                                 				ReadyForTestWork_UserStoryCount,
			                                 			sprintHoursPieChartData[0]),
			                                 		CreateWorkItemCountPieChartData(string.Empty, 0,
			                                 		                                sprintHoursPieChartData[1]),
			                                 		CreateWorkItemCountPieChartData(
			                                 			Resources.WorkItemState_Active,
			                                 			userStoryCountChartViewModel.ActiveWork_UserStoryCount,
			                                 			sprintHoursPieChartData[2]),
			                                 		CreateWorkItemCountPieChartData(
			                                 			Resources.WorkItemState_NotDone,
			                                 			userStoryCountChartViewModel.NotDoneWork_UserStoryCount,
			                                 			sprintHoursPieChartData[3])
			                                 	};
			userStoryCountChartViewModel.Stub(x => x.Caption).Return("User Stories");
			userStoryCountChartViewModel.Stub(x => x.PieChartData).Return(userStoryCountPieChartData);
			Bind<IUserStoryCountChartViewModel>().ToConstant(userStoryCountChartViewModel);

			Bind<IRemainingWorkStatusEvaluator>().To<TestAssetLibrary.HardcodedRemainingWorkStatusEvaluator>().Using<SingletonBehavior>();
			Bind<ITeamMembersListViewModel>().ToConstant(teamMembersListViewModel);
			Bind<ISprintTitleViewModel>().ToConstant(sprintTitleViewModel);
			Bind<ISprintStatsViewModel>().ToConstant(sprintStatsViewModel);
			Bind<IMonitorViewModel>().ToConstant(monitorViewModel);
		}

		private static IWorkItemHoursPieChartData CreateWorkItemHoursPieChartData(string stateName, double value)
		{
			var stub = MockRepository.GenerateStub<IWorkItemHoursPieChartData>();

			stub.StateName = stateName;
			stub.Value = value;
			stub.Stub(x => x.ValueIsHours).Return(false);

			return stub;
		}

		private static IWorkItemCountPieChartData CreateWorkItemCountPieChartData(string stateName, int value, IWorkItemHoursPieChartData timeDimension)
		{
			var stub = MockRepository.GenerateStub<IWorkItemCountPieChartData>();

			stub.StateName = stateName;
			stub.Value = value;
			stub.Stub(x => x.ValueIsHours).Return(false);
			stub.TimeDimension = timeDimension;
			stub.Stub(x => x.AverageTimePerItem).Return(timeDimension.Value / value);

			return stub;
		}
	}
}